module nazo.date;
/**
 * unixtimeとd_timeの相互変換とd_timeとISO8610形式(yyyy-MM-ddThh:mm:ssZ)の相互変換を提供します。
 * 是をインポートすると自動的にstd.dateもインポートされます。
 * History:
 *          0.0.0.1 バージョン付け開始
 * Authors: Nazo
 * Version: 0.0.0.1
 * License: Public Domain
 */
import std.string, std.stdio, std.conv, std.contracts, core.memory;
public import std.date;//一緒に読み込む

//tをk桁まで0でパディングする
private string time2str(int t,int k){
  char[] rv = (cast(char*)GC.malloc(k*char.sizeof))[0..k];//new char[k];
  for(;k;){
    rv[--k] = t?cast(char)((t%10)+'0'):'0';
    t/=10;
  }
  return assumeUnique(rv);
}

unittest{
  assert(time2str(1,2) == "01");
  assert(time2str(0,2) == "00");
  assert(time2str(10,2) == "10");
}

///日付をyyyyMMddの形でダンプします。
///Bugs: Too slow
string dumpDate(d_time datetime){
  return time2str(YearFromTime(datetime),4)~time2str(MonthFromTime(datetime)+1,2)~time2str(DateFromTime(datetime),2);
}

///日付をyyyyMMddの形でダンプします。
string dumpDate(const(Date)* d){
  return time2str(d.year,4)~time2str(d.month,2)~time2str(d.day,2);
}

d_time parse(Date* dp){
  d_time n;
  d_time day;
  d_time time;

  try{
    time = MakeTime(dp.hour, dp.minute, dp.second, dp.ms);
    if (dp.tzcorrection == Date.tzcorrection.init)
      time -= LocalTZA;
    else
      time += cast(d_time)(dp.tzcorrection / 100) * msPerHour + cast(d_time)(dp.tzcorrection % 100) * msPerMinute;

    day = MakeDay(dp.year, dp.month - 1, dp.day);
    n = MakeDate(day,time);
    n = TimeClip(n);
  }catch{
    n=d_time_nan;
  }
  return n;
}

///文字列なunixtimeの時刻をISO8601形式に変換する。
///…ってか是ここに必要か?
string time2trim(string time){
  int i=std.conv.toInt(time);
  return toISO8610String(getUTCtimeFromUtime(i));
}

///時刻をISO8601形式に変換する(time2trimの修正版)
///Bugs: OS非依存にする為にstd.dateの非公開APIを利用している
string toISO8610String(d_time time){
  if (time == d_time_nan)
    return "Invalid Date";
  d_time dst=DaylightSavingTA(time);
  d_time offset = LocalTZA + dst;
  d_time t = time + offset;
  string tz="+";
  if(offset<0){
    tz="-";
    offset=-offset;
  }
  if(offset==0){
    tz~="Z";
  }else{
    int mn=cast(int)(offset / msPerMinute);
    tz~=time2str(mn/60,2);
    tz~=":";
    tz~=time2str(mn%60,2);
  }
  return time2str(YearFromTime(t),4)~"-"~time2str(MonthFromTime(t)+1,2)~"-"~time2str(DateFromTime(t),2)~"T"
         ~time2str(cast(int)HourFromTime(t),2)~":"~time2str(cast(int)MinFromTime(t),2)~":"~time2str(cast(int)SecFromTime(t),2)~tz;
}

///時刻をISO8610形式からd_timeに変換する
///Bugs: OS非依存にする為にstd.dateの非公開APIを利用している
d_time getUTCtimeFromISO8610String(string time){

  int h;//時差の時
  int m;//時差の分
  if(time[19]!='Z'){
    h=.toInt(time[20..22]);
    m=.toInt(time[23..25]);
    if(time[19]=='+'){
      h=-h;
      m=-m;
    }
  }

  return MakeDate(MakeDay(.toInt(time[0..4]),.toInt(time[5..7])-1,.toInt(time[8..10])),MakeTime(.toInt(time[11..13])+h,.toInt(time[14..16])+m,.toInt(time[17..19]),0));
}

///UnixTimeからd_timeを取得。OS非依存。
d_time getUTCtimeFromUtime(int unixtime){
  return unixtime * cast(d_time)TicksPerSecond +
         (0 / (1000000 / cast(d_time)TicksPerSecond));
}

///d_timeからUnixTimeを取得。OS非依存。
int toUtime(d_time time){
  return cast(int)(time / cast(d_time)TicksPerSecond -
         (0 / (1000000 / cast(d_time)TicksPerSecond)));
}
